#ifndef RAFT_PACKET
#define RAFT_PACKET
#define RPC_CANDIDATE 1
#define RPC_HEARTBEATS 2
#define RPC_LOGAPPEND 3
#define RPC_CANDIDATE_RESP 4
#define RPC_HEARTBEATS_RESP 5
#define RPC_LOGAPPEND_RESP 6
#include "net/ip/uip.h"
#include "raft-log.h"
// #include "net/ipv6/simple-udp.h"
#include "ffz/bit-ops.h"

/**
 * getSendBuffer
 * @return uint8_t sendbuffer[100];
 * */
uint8_t *getSendBuffer();

/**
 * Initialize the sendconn
 * */
void initSendConnection(struct uip_udp_conn *conn);
/**
 * Initialize the recvconn
 * */
void initRecvConnection(struct uip_udp_conn *conn);
/**
 * Initialize the broadcast process
 */
void initBroadCastProcess(struct process *process);

/**
 * send broadcast to other node
 * */
void raftPacketSendBroadcast(uint8_t *data, uint16_t datalen);
/**
 * send unicast to other node
 * */
void raftPacketSendUnicast(uint8_t *data, uint16_t datalen, uip_ipaddr_t *ip);

//RPC packet
/**
 * get RPC type from a packet
 * @param data the packet
 * @return the RPC type
 * */
uint8_t getRPCType(const uint8_t *data);
//RPC Candidate request
/**
 * generate a candidate packet
 * Byte [0,1) type to show this is a candidate RPC
 * Byte [1,3) term
 * Byte [3,5) candidateId
 * Byte [5,7) lastLogIndex
 * Byte [7,9) lastLogTerm
 * @param term term index, which the candidate decide to join
 * @param candiateId the node Id
 * @param lastLogIndex logs in the candidate, get the newest log's index
 * @param lastLogTerm logs in the candidate, get the newest log's term
 * @param data these information will be filled in the data's position
 * */
void createRaftPacketCandidate(uint16_t term, uint16_t candidateId, uint16_t lastLogIndex, uint16_t lastLogTerm, uint8_t *data);
/**
 * get each value from the candidate packet
 * @param term* term index's pointer, which the candidate decide to join
 * @param candidateId* candidateId value's pointer
 * @param lastLogIndex* newest log's index of the candidate 
 * @param lastLogTerm* newest log's term of the candidate
 * */
void extractRaftPacketCandidate(uint16_t *term, uint16_t *candidateId, uint16_t *lastLogIndex, uint16_t *lastLogTerm, const uint8_t *data);
//RPC Candidate response
/**
 * generate a candidate response packet
 * Byte [0,1) type to show this is a candidate response RPC 
 * Byte [1,3) responser's term index
 * Byte [3] did the responser give the vote for the candidate 
 * Byte [4,6) senderId 
 * @param term the current term of this node
 * @param voteGranted voteGranted == 1 : the candidate get the vote from this node
 * */
void createRaftPacketCandidateResp(uint16_t term, uint8_t voteGranted, uint16_t senderId, uint8_t *data);
/**
 * get each value from the candidate response packet
 * @param term the current term of response node
 * @param voteGranted voteGranted == 1 response node has voted for us?  
 * */
void extractRaftPacketCandidateResp(uint16_t *term, uint8_t *voteGranted, uint16_t *senderId, const uint8_t *data);
//RPC Heartbeats
//RPC Heartbeats request
/**
 * [0] the package's type
 * [1,2] the term
 * [3,4] the leaderId
 * [5,6] the prevIndex
 * [7,8] the prevTerm
 * [9,10] the commitIndex
 * [11] is this packet has entry
 * [12,13] entry's index
 * [14,15] entry's term
 * [16] entry's status
 * [17] entry's action
 * @param term display the term that we have
 * @param leaderId the leader's id
 * @param prevIndex 
 * @param prevTerm
 * @param commitIndex
 * @param hasEntry
 * @param entry
 * @param data the package's address
 * */
void createRaftPacketHeartbeats(uint16_t term, uint16_t leaderId, uint16_t prevIndex, uint16_t prevTerm, uint16_t commitIndex, uint8_t hasEntry, RaftLog *entry, uint8_t *data);
/**
 * extract heartbeats data from packet
 * */
void extractRaftPacketHeartbeats(uint16_t *term, uint16_t *leaderId, uint16_t *prevIndex, uint16_t *prevTerm, uint16_t *commitIndex, uint8_t *hasEntry, RaftLog *entry, const uint8_t *data);
//RPC Heartbeats response
/**
 * [0] the package's type
 * [1,2] the term
 * [3] the success
 * [4,5] the matchIndex
 * [6,7] the senderId
 * */
void createRaftPacketHeartbeatsResp(uint16_t term, uint8_t success, uint16_t matchIndex, uint16_t senderId, uint8_t *data);
void extractRaftPacketHeartbeatsResp(uint16_t *term, uint8_t *success, uint16_t *matchIndex, uint16_t *senderId, const uint8_t *data);
#endif